﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Collections;
using System.Globalization;

namespace SPBusiness
{
    public class SPEventControl
    {

        private class BasicItem : IComparer, IEqualityComparer, IEquatable<BasicItem>, IEqualityComparer<BasicItem>,
            IComparer<BasicItem>, IComparable, IComparable<BasicItem>
        {            
            public DateTime Time { get; set; }
            public string Event { get; set; }

            private int _ID;
            public int ID
            {
                get
                {

                    return _ID;
                }
                set
                {
                    Time = DateTime.Now;
                    _ID = value;
                    _InternalID = Event + value.ToString() + Time.ToString();

                }

            }

            private string _InternalID;

            public BasicItem()
            {
            }

            public BasicItem(CultureInfo myCulture)
            {
            }

            public BasicItem(int pID, string pEvent)
            {
                Time = DateTime.Now;
                Event = pEvent;
                ID = pID;
            }

            int IComparer.Compare(Object x, Object y)
            {

                BasicItem a = (BasicItem)x;
                BasicItem b = (BasicItem)y;

                return string.Compare(a._InternalID, b._InternalID);
            }

            bool IEqualityComparer.Equals(object x, object y)
            {
                BasicItem a = (BasicItem)x;
                BasicItem b = (BasicItem)y;

                return a._InternalID == b._InternalID;

            }

            int IEqualityComparer.GetHashCode(object obj)
            {
                BasicItem a = (BasicItem)obj;

                return a._InternalID.GetHashCode();
            }

            public override int GetHashCode()
            {
                return this._InternalID.GetHashCode();
            }

            bool IEquatable<BasicItem>.Equals(BasicItem other)
            {
                return this._InternalID == other._InternalID;
            }

            bool IEqualityComparer<BasicItem>.Equals(BasicItem x, BasicItem y)
            {
                return x._InternalID == y._InternalID;
            }

            int IEqualityComparer<BasicItem>.GetHashCode(BasicItem obj)
            {
                return obj._InternalID.GetHashCode();
            }

            int IComparer<BasicItem>.Compare(BasicItem x, BasicItem y)
            {
                return string.Compare(x._InternalID, y._InternalID);
            }

            int IComparable.CompareTo(object obj)
            {

                BasicItem a = (BasicItem)obj;

                return this._InternalID.CompareTo(a._InternalID);
            }

            int IComparable<BasicItem>.CompareTo(BasicItem other)
            {
                return this._InternalID.CompareTo(other._InternalID);
            }
        }

        private SynchronizedCollection<BasicItem> RunningIDs = new SynchronizedCollection<BasicItem>();

        private void AddItem(Int32 pID, string pEvent)
        {
            try
            {
                BasicItem vBasicItem = new BasicItem(pID, pEvent);

                RunningIDs.Add(vBasicItem);

            }
            catch (Exception ex)
            {
                Logging.LogMessase(typeof(SPEventControl).Namespace, typeof(SPEventControl).Name, "AddItem", ex);
                throw;
            }
        }

        public bool CanExecute(Int32 pID, string pEvent)
        {
            try
            {
                System.Threading.Monitor.Enter(this);

                bool vReturn = false;

                CleanUpOld(pID, pEvent);
                AddItem(pID, pEvent);

                IEnumerable<BasicItem> vBasicItems = RunningIDs.Where(x => x.ID == pID && x.Event == pEvent);

                if (vBasicItems.Count() == 2)
                {
                    vReturn = true;
                    CleanUpAll(pID, pEvent);
                }
                else if (vBasicItems.Count() > 2)
                {
                    CleanUpAll(pID, pEvent);
                    throw new Exception("Quantidade de execuções não permitidas!");
                }

                return vReturn;
            }
            catch (Exception ex)
            {
                Logging.LogMessase(typeof(SPEventControl).Namespace, typeof(SPEventControl).Name, "CanExecute", ex);
            }
            finally
            {
                System.Threading.Monitor.Exit(this);
            }
            return false;
        }

        private void CleanUpAll(Int32 pID, string pEvent)
        {
            try
            {
                IEnumerable<BasicItem> vBasicItems = RunningIDs.Where(x => x.ID == pID && x.Event == pEvent).ToList();

                foreach (BasicItem vBasicItem in vBasicItems)
                {
                    RunningIDs.Remove(vBasicItem);
                }
            }
            catch (Exception ex)
            {
                Logging.LogMessase(typeof(SPEventControl).Namespace, typeof(SPEventControl).Name, "CleanUpAll", ex);
                throw;
            }
        }

        private void CleanUpOld(Int32 pID, string pEvent)
        {
            try
            {
                IEnumerable<BasicItem> vBasicItems = RunningIDs.Where(x => x.ID == pID && x.Event == pEvent && x.Time < DateTime.Now.AddSeconds(-5)).ToList();

                foreach (BasicItem vBasicItem in vBasicItems)
                {
                    RunningIDs.Remove(vBasicItem);
                }
            }
            catch (Exception ex)
            {
                Logging.LogMessase(typeof(SPEventControl).Namespace, typeof(SPEventControl).Name, "CleanUpOld", ex);
                throw;
            }
        }

    }
}
